package tools

import (
	"bufio"
	"context"
	"fmt"
	"os"
	"os/exec"
	"runtime"
	"strings"
	"time"

	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
)

// CommandExecutorConfig 命令执行器的专用配置
type CommandExecutorConfig struct {
	CommandTimeout int // 命令执行超时时间(秒)
}

// DefaultCommandExecutorConfig 返回默认的命令执行器配置
func DefaultCommandExecutorConfig() CommandExecutorConfig {
	return CommandExecutorConfig{
		CommandTimeout: 30,
	}
}

// CommandExecutor 实现了执行shell命令的工具
// 该工具允许ReAct智能体执行系统命令，如文件操作、程序运行等
// 注意：使用此工具需要谨慎，确保命令的安全性
type CommandExecutor struct {
	config CommandExecutorConfig // 命令执行器专用配置
}

// Name 返回工具的唯一标识名称
// 智能体通过此名称来调用该工具
func (ce *CommandExecutor) Name() string {
	return "execute_command"
}

// Description 返回工具的功能描述
// 该描述会被发送给AI模型，帮助其理解工具的用途和使用场景
func (ce *CommandExecutor) Description() string {
	return fmt.Sprintf(`执行shell命令并返回输出结果。支持跨平台命令执行（Windows/Linux/macOS），提供系统级操作能力。

**参数说明：**
- command (string, 必需): 要执行的shell命令字符串
  - Linux/macOS支持: "ls -la", "pwd", "echo hello", "ps aux | grep nginx"
  - Windows支持: "dir", "cd", "echo hello", "tasklist | findstr nginx"
  - 支持管道和重定向操作
  - 命令执行超时时间: %d秒

**使用示例：**
`+"```json"+`
{
  "type": "action",
  "action": "execute_command",
  "parameters": {
    "command": "ls -la"
  }
}
`+"```"+`

`+"```json"+`
{
  "type": "action",
  "action": "execute_command",
  "parameters": {
    "command": "pwd && ls"
  }
}
`+"```"+`

`+"```json"+`
{
  "type": "action",
  "action": "execute_command",
  "parameters": {
    "command": "dir /s"
  }
}
`+"```"+`

**返回结果：**
- 成功: 命令输出内容
- 失败: 错误信息和输出内容
- 取消: "命令执行已取消"`, ce.config.CommandTimeout)
}

// confirmCommand 请求用户确认是否执行命令
// 返回true表示用户确认执行，false表示用户取消
func (ce *CommandExecutor) confirmCommand(command string) bool {
	// 为了测试目的，可以设置环境变量跳过确认
	if os.Getenv("AISH_SKIP_CONFIRM") == "true" {
		return true
	}

	reader := bufio.NewReader(os.Stdin)

	fmt.Printf("\n[WARNING] 确认执行命令: %s\n", command)
	fmt.Print("请确认是否执行？(y/N): ")

	input, err := reader.ReadString('\n')
	if err != nil {
		return false
	}

	input = strings.TrimSpace(strings.ToLower(input))
	return input == "y" || input == "yes"
}

// Execute 执行具体的shell命令
// 该方法是工具的核心功能，负责解析参数并执行命令
func (ce *CommandExecutor) Execute(args map[string]interface{}) (string, error) {
	// 从参数中提取要执行的命令字符串
	command, ok := args["command"].(string)
	if !ok {
		// 参数验证失败，返回错误
		return "", fmt.Errorf("command parameter is required and must be string")
	}

	// 清理命令字符串，去除潜在的危险字符
	command = strings.TrimSpace(command)
	if command == "" {
		return "", fmt.Errorf("command cannot be empty")
	}

	// 请求用户确认
	if !ce.confirmCommand(command) {
		return "命令执行已取消", nil
	}

	// 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(ce.config.CommandTimeout)*time.Second)
	defer cancel()

	// 根据操作系统类型选择合适的shell
	var cmd *exec.Cmd
	if runtime.GOOS == "windows" {
		// Windows系统使用cmd.exe
		cmd = exec.CommandContext(ctx, "cmd", "/C", command)
	} else {
		// Linux/macOS系统使用sh -c
		cmd = exec.CommandContext(ctx, "sh", "-c", command)
	}

	// 获取命令的标准输出和标准错误输出
	output, err := cmd.CombinedOutput()

	// 处理Windows下的编码问题
	outputStr := ce.convertEncoding(output)

	if err != nil {
		// 检查是否是超时错误
		if ctx.Err() == context.DeadlineExceeded {
			return outputStr, fmt.Errorf("执行命令超时: %d秒", ce.config.CommandTimeout)
		}
		// 如果有输出内容，将其包含在错误信息中
		if strings.TrimSpace(outputStr) != "" {
			return outputStr, fmt.Errorf("执行命令失败: %v", strings.TrimSpace(outputStr))
		}
		// 命令执行失败，返回原始错误信息
		return outputStr, fmt.Errorf("执行命令失败: %v", err)
	}

	// 命令执行成功，返回输出结果
	return outputStr, nil
}

// convertEncoding 处理Windows下的编码转换问题
// 在Windows系统下，命令行输出通常是GBK编码，需要转换为UTF-8
func (ce *CommandExecutor) convertEncoding(data []byte) string {
	// 如果不是Windows系统，直接返回UTF-8字符串
	if runtime.GOOS != "windows" {
		return string(data)
	}

	// 尝试将GBK编码转换为UTF-8
	decoder := simplifiedchinese.GBK.NewDecoder()
	utf8Data, _, err := transform.Bytes(decoder, data)
	if err != nil {
		// 如果转换失败，可能原本就是UTF-8编码，直接返回
		return string(data)
	}

	return string(utf8Data)
}

// NewCommandExecutor 创建并返回一个新的CommandExecutor实例
// 这是一个工厂函数，用于初始化命令执行器工具
func NewCommandExecutor() *CommandExecutor {
	return &CommandExecutor{
		config: DefaultCommandExecutorConfig(),
	}
}

// NewCommandExecutorWithTimeout 使用指定的超时时间创建CommandExecutor实例
func NewCommandExecutorWithTimeout(commandTimeout int) *CommandExecutor {
	return &CommandExecutor{
		config: CommandExecutorConfig{
			CommandTimeout: commandTimeout,
		},
	}
}
